package com.jade.modules.workflow.impl;

import java.util.List;

import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import com.jade.framework.base.criterion.Criteria;
import com.jade.framework.base.criterion.Restrictions;
import com.jade.framework.base.criterion.sql.SqlUtils;
import com.jade.framework.base.util.PagingList;
import com.jade.modules.workflow.*;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;

/**
 * 采用JPA方式实现的流程数据存储接口。
 */
//@Named ("module_workflowDao")
public class JpaFlowDao
        implements FlowDao
{
    @PersistenceContext (unitName = "default")
    protected EntityManager entityManager;

    @Caching (evict = {
            @CacheEvict (value = "module.workflow.apply.g", key = "#context.type + '_' + #context.entity")})
    public void addContext(FlowContext context)
            throws FlowException
    {
        entityManager.persist(context);
    }

    @Caching (evict = {
            @CacheEvict (value = "module.workflow.apply.g", key = "#context.type + '_' + #context.entity")})
    public void updateContext(FlowContext context)
            throws FlowException
    {
        entityManager.merge(context);
    }

    @Caching (evict = {
            @CacheEvict (value = "module.workflow.apply.g", key = "#context.type + '_' + #context.entity")})
    public void removeContext(FlowContext context)
            throws FlowException
    {
        FlowContext old = entityManager.find(FlowContext.class, context.getId());
        if (old != null) {
            entityManager.remove(old);
        }
    }

    @Cacheable (value = "module.workflow.context.g", key = "#type + '_' + #entity")
    public FlowContext getContext(String type, String entity)
    {
        String sql = "SELECT context FROM com.jade.modules.workflow.FlowContext context WHERE type=:type AND entity=:entity";
        Query query = entityManager.createQuery(sql);
        query.setParameter("type", type);
        query.setParameter("entity", entity);
        return SqlUtils.getSingleResult(query);
    }

    @Caching (evict = {@CacheEvict (value = "module.workflow.apply.g", key = "#apply.id"),
            @CacheEvict (value = "module.workflow.apply.q", key = "#apply.type + '[%GRP%]'")})
    public void addApply(FlowApply apply)
            throws FlowException
    {
        entityManager.persist(apply);
    }

    @Caching (evict = {@CacheEvict (value = "module.workflow.apply.g", key = "#apply.id"),
            @CacheEvict (value = "module.workflow.apply.q", key = "#apply.type + '[%GRP%]'")})
    public void updateApply(FlowApply apply)
            throws FlowException
    {
        entityManager.merge(apply);
    }

    @Caching (evict = {@CacheEvict (value = "module.workflow.apply.g", key = "#apply.id"),
            @CacheEvict (value = "module.workflow.apply.q", key = "#apply.type + '[%GRP%]'")})
    public void removeApply(FlowApply apply)
            throws FlowException
    {
        FlowApply old = entityManager.find(FlowApply.class, apply.getId());
        if (old != null) {
            entityManager.remove(old);
        }

    }

    @Cacheable (value = "module.workflow.apply.g", key = "#applyId")
    public FlowApply getApply(long applyId)
    {
        return entityManager.find(FlowApply.class, applyId);
    }

    private static final String SQL_APPLY = "SELECT apply FROM com.jade.modules.workflow.FlowApply apply";

    @Cacheable (value = "module.workflow.apply.q", key = "#type + '[%GRP%]' + #criteria")
    public PagingList<FlowApply> queryApply(String type, Criteria criteria)
    {
        criteria.add(Restrictions.eq("type", type));
        return SqlUtils.sqlQuery(SQL_APPLY, entityManager, criteria);
    }

    @Caching (evict = {@CacheEvict (value = "module.workflow.role.g", key = "#role.type + '_' + #role.step"),
            @CacheEvict (value = "module.workflow.role.l", key = "#role.type + '_all'")})
    public void addRole(FlowRole role)
            throws FlowException
    {
        entityManager.persist(role);
    }

    @Caching (evict = {@CacheEvict (value = "module.workflow.role.g", key = "#role.type + '_' + #role.step"),
            @CacheEvict (value = "module.workflow.role.l", key = "#role.type + '_all'")})
    public void updateRole(FlowRole role)
            throws FlowException
    {
        entityManager.merge(role);
    }

    @Caching (evict = {@CacheEvict (value = "module.workflow.role.g", key = "type + '_' + step"),
            @CacheEvict (value = "module.workflow.role.l", key = "#type + '_all'")})
    public void removeRole(String type, int step)
            throws FlowException
    {
        String sql = "DELETE FROM com.jade.modules.workflow.FlowRole role WHERE type=:type";
        if (step > 0) {
            sql += " AND step=:step";
        }
        Query query = entityManager.createQuery(sql);
        query.setParameter("type", type);
        query.setParameter("step", step);
        query.executeUpdate();
    }

    @Cacheable (value = "module.workflow.role.l", key = "#type + '_all'")
    public List<FlowRole> listRole(String type)
    {
        String sql = "SELECT role FROM com.jade.modules.workflow.FlowRole role WHERE type=:type ORDER BY step ASC";
        Query query = entityManager.createQuery(sql);
        query.setParameter("type", type);
        return query.getResultList();
    }

    @Cacheable (value = "module.workflow.role.g", key = "#type + '_' + #step")
    public FlowRole getRole(String type, int step)
    {
        String sql = "SELECT role FROM com.jade.modules.workflow.FlowRole role WHERE type=:type AND step=:step";
        Query query = entityManager.createQuery(sql);
        query.setParameter("type", type);
        query.setParameter("step", step);
        return SqlUtils.getSingleResult(query);
    }
}
